/**
 * 全局错误处理中间件
 * EndoSight-UC 医疗AI系统
 *
 * 提供统一的错误处理、分类、恢复和日志记录
 */

import winston from 'winston';
import {
  classifyError,
  ErrorSeverity,
  createError,
  AppError
} from '../utils/errorTypes.js';

// 配置日志记录器
const logger = winston.createLogger({
  level: 'info',
  format: winston.format.combine(
    winston.format.timestamp(),
    winston.format.errors({ stack: true }),
    winston.format.json()
  ),
  transports: [
    new winston.transports.Console({
      format: winston.format.combine(
        winston.format.colorize(),
        winston.format.simple()
      )
    }),
    new winston.transports.File({
      filename: 'logs/errors.log',
      level: 'error'
    }),
    new winston.transports.File({
      filename: 'logs/security.log',
      level: 'warn'
    }),
    new winston.transports.File({
      filename: 'logs/combined.log'
    })
  ]
});

// 熔断器状态
const circuitBreakers = new Map();

// 熔断器配置
const CIRCUIT_BREAKER_CONFIG = {
  failureThreshold: 5,        // 失败阈值
  resetTimeout: 60000,        // 重置超时 (1分钟)
  monitoringPeriod: 30000,    // 监控周期 (30秒)
  halfOpenMaxCalls: 3         // 半开状态最大调用数
};

// 熔断器类
class CircuitBreaker {
  constructor(serviceName) {
    this.serviceName = serviceName;
    this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
    this.failureCount = 0;
    this.lastFailureTime = null;
    this.successCount = 0;
    this.halfOpenCallCount = 0;
  }

  async execute(operation) {
    // 检查熔断器状态
    if (this.state === 'OPEN') {
      if (Date.now() - this.lastFailureTime > CIRCUIT_BREAKER_CONFIG.resetTimeout) {
        this.state = 'HALF_OPEN';
        this.halfOpenCallCount = 0;
        logger.info(`熔断器 ${this.serviceName} 进入半开状态`);
      } else {
        throw createError.circuitBreakerOpen(
          `服务 ${this.serviceName} 熔断器已开启`,
          {
            serviceName: this.serviceName,
            state: this.state,
            nextRetryTime: this.lastFailureTime + CIRCUIT_BREAKER_CONFIG.resetTimeout
          }
        );
      }
    }

    try {
      const result = await operation();

      // 操作成功，更新状态
      if (this.state === 'HALF_OPEN') {
        this.halfOpenCallCount++;
        if (this.halfOpenCallCount >= CIRCUIT_BREAKER_CONFIG.halfOpenMaxCalls) {
          this.reset();
          logger.info(`熔断器 ${this.serviceName} 已关闭`);
        }
      } else {
        this.successCount++;
        if (this.successCount > 10) { // 连续成功多次后减少失败计数
          this.failureCount = Math.max(0, this.failureCount - 1);
        }
      }

      return result;
    } catch (error) {
      this.recordFailure();
      throw error;
    }
  }

  recordFailure() {
    this.failureCount++;
    this.lastFailureTime = Date.now();

    if (this.state === 'HALF_OPEN') {
      this.state = 'OPEN';
      logger.warn(`熔断器 ${this.serviceName} 再次开启`);
    } else if (this.failureCount >= CIRCUIT_BREAKER_CONFIG.failureThreshold) {
      this.state = 'OPEN';
      logger.warn(`熔断器 ${this.serviceName} 开启`, {
        failureCount: this.failureCount,
        threshold: CIRCUIT_BREAKER_CONFIG.failureThreshold
      });
    }
  }

  reset() {
    this.state = 'CLOSED';
    this.failureCount = 0;
    this.successCount = 0;
    this.halfOpenCallCount = 0;
    this.lastFailureTime = null;
  }

  getState() {
    return {
      serviceName: this.serviceName,
      state: this.state,
      failureCount: this.failureCount,
      successCount: this.successCount,
      lastFailureTime: this.lastFailureTime
    };
  }
}

// 获取或创建熔断器
const getCircuitBreaker = (serviceName) => {
  if (!circuitBreakers.has(serviceName)) {
    circuitBreakers.set(serviceName, new CircuitBreaker(serviceName));
  }
  return circuitBreakers.get(serviceName);
};

// 错误恢复策略
const recoveryStrategies = {
  // 数据库连接错误恢复
  databaseConnection: async (error, req, res, next) => {
    logger.warn('尝试恢复数据库连接...');
    try {
      const db = (await import('../config/database.js')).default;
      await db.testConnection();
      logger.info('数据库连接恢复成功');
      return next(); // 重试请求
    } catch (recoveryError) {
      logger.error('数据库连接恢复失败:', recoveryError);
      return next(error); // 继续原错误处理
    }
  },

  // AI推理服务错误恢复
  aiInference: async (error, req, res, next) => {
    logger.warn('尝试使用备用AI推理策略...');
    try {
      // 实现降级策略：返回快速评估结果
      return res.status(200).json({
        success: true,
        message: 'AI服务暂时不可用，已使用快速评估模式',
        data: {
          score: 2.0,
          severity: 'mild',
          confidence: 0.6,
          model_version: 'fallback-v1.0',
          is_fallback: true,
          analysis_details: {
            message: 'AI推理服务暂时不可用，已使用基于规则的快速评估',
            recommendations: ['建议稍后重新进行AI评分', '当前评估仅供参考']
          }
        }
      });
    } catch (recoveryError) {
      logger.error('AI推理恢复策略失败:', recoveryError);
      return next(error);
    }
  },

  // 临时服务不可用恢复
  serviceUnavailable: async (error, req, res, next) => {
    logger.warn('服务暂时不可用，建议用户稍后重试');
    return res.status(503).json({
      success: false,
      message: '服务暂时不可用，请稍后重试',
      data: {
        retry_after: 30, // 建议重试间隔（秒）
        error_code: 'SERVICE_TEMPORARILY_UNAVAILABLE'
      }
    });
  },

  // 默认恢复策略
  default: async (error, req, res, next) => {
    return next(error);
  }
};

// 错误严重程度处理
const severityHandlers = {
  [ErrorSeverity.CRITICAL]: async (error, req, res, next) => {
    // 关键错误：立即记录并尝试安全关闭相关功能
    logger.error('关键错误发生，触发紧急处理:', error);

    // 记录到安全日志
    logger.warn('安全事件:', {
      type: 'critical_error',
      error: error.toJSON(),
      request: {
        ip: req.ip,
        userAgent: req.get('User-Agent'),
        url: req.url,
        method: req.method
      }
    });

    return res.status(500).json({
      success: false,
      message: '系统遇到关键错误，请联系管理员',
      data: {
        error_code: 'CRITICAL_ERROR',
        timestamp: new Date().toISOString()
      }
    });
  },

  [ErrorSeverity.HIGH]: async (error, req, res, next) => {
    // 高级错误：详细记录并尝试恢复
    logger.error('高级错误发生:', error);

    // 尝试恢复策略
    const classification = classifyError(error);
    const recoveryStrategy = recoveryStrategies[classification.category] || recoveryStrategies.default;

    return recoveryStrategy(error, req, res, next);
  },

  [ErrorSeverity.MEDIUM]: async (error, req, res, next) => {
    // 中级错误：记录并继续处理
    logger.warn('中级错误发生:', error);
    return next(error);
  },

  [ErrorSeverity.LOW]: async (error, req, res, next) => {
    // 低级错误：简单记录
    logger.info('低级错误发生:', error.message);
    return next(error);
  }
};

// 主要错误处理中间件
export const errorHandler = async (error, req, res, next) => {
  // 确保error是一个AppError实例
  const appError = error instanceof AppError ? error : new AppError(
    error.message || '服务器内部错误',
    error.statusCode || 500,
    error.code || 'INTERNAL_ERROR',
    error.details
  );

  // 错误分类
  const classification = classifyError(appError);

  // 增强错误信息
  const enhancedError = {
    ...appError.toJSON(),
    classification,
    request: {
      method: req.method,
      url: req.url,
      ip: req.ip,
      userAgent: req.get('User-Agent'),
      userId: req.user?.doctor_id,
      timestamp: new Date().toISOString()
    }
  };

  // 根据严重程度处理
  const severityHandler = severityHandlers[classification.severity] || severityHandlers[ErrorSeverity.MEDIUM];
  await severityHandler(appError, req, res, next);

  // 如果没有通过严重程度处理返回，则继续标准错误处理
  if (!res.headersSent) {
    // 安全错误处理
    if (classification.category === 'security') {
      logger.warn('安全错误:', enhancedError);

      return res.status(appError.statusCode).json({
        success: false,
        message: appError.message,
        data: {
          error_code: appError.code,
          severity: classification.severity,
          timestamp: appError.timestamp
        }
      });
    }

    // 标准错误响应
    const statusCode = appError.statusCode;
    let message = appError.message;

    // 生产环境下隐藏敏感错误信息
    if (process.env.NODE_ENV === 'production' && statusCode === 500) {
      message = '服务器内部错误';
    }

    res.status(statusCode).json({
      success: false,
      message: message,
      data: {
        error_code: appError.code,
        ...(process.env.NODE_ENV === 'development' && {
          details: appError.details,
          stack: appError.stack,
          classification: classification
        }),
        timestamp: appError.timestamp
      }
    });
  }

  // 记录错误统计
  logErrorStatistics(enhancedError);
};

// 记录错误统计信息
const logErrorStatistics = (errorInfo) => {
  const stats = {
    timestamp: new Date().toISOString(),
    errorType: errorInfo.classification.type,
    category: errorInfo.classification.category,
    severity: errorInfo.classification.severity,
    statusCode: errorInfo.statusCode,
    isOperational: errorInfo.classification.isOperational
  };

  logger.info('错误统计:', stats);

  // 在生产环境中，这里可以发送到监控系统
  if (process.env.NODE_ENV === 'production') {
    // TODO: 集成监控系统 (如 Prometheus, Sentry 等)
  }
};

// 异步错误处理包装器
export const asyncHandler = (fn) => {
  return (req, res, next) => {
    Promise.resolve(fn(req, res, next)).catch(next);
  };
};

// 带熔断器的服务调用
export const withCircuitBreaker = (serviceName, operation) => {
  const circuitBreaker = getCircuitBreaker(serviceName);
  return circuitBreaker.execute(operation);
};

// 获取所有熔断器状态
export const getCircuitBreakersStatus = () => {
  return Array.from(circuitBreakers.values()).map(cb => cb.getState());
};

// 重置特定熔断器
export const resetCircuitBreaker = (serviceName) => {
  const circuitBreaker = circuitBreakers.get(serviceName);
  if (circuitBreaker) {
    circuitBreaker.reset();
    logger.info(`熔断器 ${serviceName} 已手动重置`);
    return true;
  }
  return false;
};

export default errorHandler;